package manager

import (
	"fmt"
	"github.com/tianjigames/fairy/constants"
	"github.com/tianjigames/fairy/dao"
	"github.com/tianjigames/fairy/model"
	"github.com/tianjigames/fairy/pojo"
	"github.com/tianjigames/fairy/template"
	"github.com/tianjigames/fairy/util"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/logger"
	"math"
	"strconv"
	"sync"
)

var (
	ItemManager *itemManager
	itemManagerOnce sync.Once
	Strength10VipLimit int //可以单次强化10次的vip等级
)

const (
	ItemMaxGemAttr          = 2 //宝石对属性的最大影响数组
	ItemIdxGemAttrLen       = 2 //宝石加成属性信息数组长度
	ItemMaxEquipAttr        = 8 //武器加成属性的最大数量
	ItemIdxEquipAttrLen     = 3 //武器加成单个属性的数组长度
	ItemIdxEquipRandAttrLen = 4 //武器加成的随机属性信息的数组长度
	ItemMaxEquipPlayAttr    = 6 //手持的武器加成属性数量
	ItemIdxEquipPlayLen = 4 //手持的武器单个加成属性信息数组长度
)

type itemManager struct {
	BaseManager
	mVirtualItemId map[constants.VirtualType]int //虚拟物品类型与物品id关系表
	equipRandAttrConst *template.Constant //装备随机属性重复概率配置常量
	equipWashCons *template.Constant //赚个屁洗练伪随机配置
}


/**
物品管理器
 */
func NewItemManager() *itemManager {
	itemManagerOnce.Do(func() {
		ItemManager = &itemManager{
			mVirtualItemId: map[constants.VirtualType]int{},
		}
	})
	return ItemManager
}

func (p *itemManager) Init()  {
	config := pitaya.GetTemplateById(template.ConstantKey,constants.Strength10VipLimitTip)
	if config != nil {
		Strength10VipLimit = config.(*template.Constant).Constant2
	}

	//获取所有的物品
	itemList := pitaya.GetTemplates(template.ItemKey)
	for _,v := range itemList {
		it := v.(*template.Item)
		if it.Type == int(constants.ItemTypeVirtual) {
			subType := model.GetVirtualTypeByValue(it.SubType)
			if subType != nil && *subType != constants.VirtualTypeInvalid && *subType != constants.VirtualTypeMaxValue {
				id,err := strconv.ParseInt(it.Id,10,32)
				if err != nil {
					logger.Log.Errorf("[ItemManager] Init failed,itemId:%s,error:%s",it.Id,err.Error())
					continue
				}
				p.mVirtualItemId[*subType] = int(id)
			}
		}
	}

	v := pitaya.GetTemplateById(template.ConstantKey,constants.EquipRandAttrConst)
	if v != nil {
		p.equipRandAttrConst = v.(*template.Constant)
	}

	v = pitaya.GetTemplateById(template.ConstantKey,constants.EquipWashConst)
	if v != nil {
		p.equipWashCons = v.(*template.Constant)
	}
}

/**
获取物品对属性的加成值
 */
func (p *itemManager) CalGemAttr(player *model.PlayerObject,item *model.CommonItem,attrFlag *constants.AttrFlag) int {
	if player == nil || item == nil || attrFlag == nil {
		return 0
	}

	gemCfg := pitaya.GetTemplateById(template.GemKey,strconv.FormatInt(int64(item.GetId()),10))
	if gemCfg == nil {
		return 0
	}

	return p.CalGemBaseAttr(player,gemCfg.(*template.Gem),attrFlag)
}

/**
获取元宝的属性值
 */
func (p *itemManager) CalGemBaseAttr(player *model.PlayerObject,gemCfg *template.Gem,attrFlag *constants.AttrFlag) int {
	if attrFlag == nil {
		return 0
	}

	nBaseValue := player.GetBaseAttr(attrFlag)
	nRet := 0
	for i := 1;i<ItemMaxGemAttr;i++ {
		pro := p.GetGemAttrConfig(gemCfg,i)
		if pro == nil || len(pro) != ItemIdxGemAttrLen {
			continue
		}

		rt := model.RefixTypeVTValue
		if pro[0] == int(*attrFlag) {
			nRet += LoadPlayerInfoManager.GetAttrResult(&rt,pro[1],nBaseValue)
		}else {
			nRet += LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrFlag,constants.GetAttrFlagByValue(pro[0]),
				&rt,pro[1],nBaseValue)
		}
	}
	return nRet
}

/**
获取gem的属性配置
 */
func (p *itemManager) GetGemAttrConfig(gemCfg *template.Gem,nIdx int) []int {
	if nIdx <= 0 || nIdx > ItemMaxGemAttr {
		return nil
	}

	switch nIdx {
	case 1:
		return gemCfg.GemPara1
	case 2:
		return gemCfg.GemPara2
	}

	return nil
}

/**
计算装备对某个属性的加成值
 */
func (p *itemManager) CalEquipAttr(player *model.PlayerObject,item *model.CommonItem,attrId *constants.AttrFlag) int {
	if player == nil || item == nil || attrId == nil {
		return 0
	}

	equipCfg := pitaya.GetTemplateById(template.EquipKey,strconv.FormatInt(int64(item.GetId()),10))
	if equipCfg == nil {
		return 0
	}

	equip := equipCfg.(*template.Equip)
	//计算装备基础属性
	nRet := p.CalEquipBaseAttr(player,item,equip,attrId)
	//强化武器等级额外加成的属性值
	nRet += p.CalStrengthLevelAddAttr(player,item,equip,attrId)
	//手持武器星级对属性的加成
	nRet += p.CalEquipStarAddAttr(player,item,attrId)

	return nRet
}

/**
计算武器的基本属性值
 */
func (p *itemManager) CalEquipBaseAttr(player *model.PlayerObject,item *model.CommonItem,equip *template.Equip,attrId *constants.AttrFlag) int {
	if player == nil || item == nil || equip == nil || attrId == nil {
		return 0
	}

	nRet := 0
	nBaseValue := player.GetBaseAttr(attrId)
	for i := 1;i<=ItemMaxEquipAttr;i++ {
		pro := p.GetEquipAttrConfig(equip,i)
		if pro == nil || len(pro) < ItemIdxEquipAttrLen {
			continue
		}

		if pro[0] == int(*attrId) {
			nRet += LoadPlayerInfoManager.GetAttrResult(model.GetRefixTypeByValue(pro[1]),pro[2],nBaseValue)
		}else{
			nRet += LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrId,constants.GetAttrFlagByValue(pro[0]),
				model.GetRefixTypeByValue(pro[1]),pro[2],nBaseValue)
		}
	}

	//随机属性
	for i:= 0;i<int(item.RandAttrCount);i++ {
		if item.RandAttrType[i] == byte(*attrId) {
			nRet += LoadPlayerInfoManager.GetAttrResult(model.GetRefixTypeByValue(int(item.RandAttrCal[i])),
				item.RandAttrValue[i],nBaseValue)
		}else {
			nRet += LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrId,constants.GetAttrFlagByValue(int(item.RandAttrType[i])),
				model.GetRefixTypeByValue(int(item.RandAttrCal[i])),item.RandAttrValue[i],nBaseValue)
		}
	}

	return nRet
}

/**
获取武器单个加成属性数组
 */
func (p *itemManager) GetEquipAttrConfig(equip *template.Equip,idx int) []int {
	if equip == nil {
		return nil
	}

	if idx <= 0 || idx > ItemMaxEquipAttr {
		return nil
	}

	switch idx {
	case 1:
		return equip.Property1
	case 2:
		return equip.Property2
	case 3:
		return equip.Property3
	case 4:
		return equip.Property4
	case 5:
		return equip.Property5
	case 6:
		return equip.Property6
	case 7:
		return equip.Property7
	case 8:
		return equip.Property8
	}
	return nil
}

/**
计算某个装备强化等级增加的加成属性值
 */
func (p *itemManager) CalStrengthLevelAddAttr(player *model.PlayerObject,item *model.CommonItem,equip *template.Equip,attrId *constants.AttrFlag) int {
	if player == nil || item == nil || equip == nil || attrId == nil || item.StrengthLevel == 0 {
		return 0
	}

	v := pitaya.GetTemplateById(template.StrengthLevelKey,strconv.FormatInt(int64(item.StrengthLevel + 1),10))
	if v == nil {
		return 0
	}

	nRet := 0
	strengthen := v.(*template.StrengthLevel)
	nBaseValue := player.GetBaseAttr(attrId)
	for i := 1;i<=ItemMaxEquipAttr;i++ {
		pro := p.GetEquipAttrConfig(equip,i)
		if pro == nil || len(pro) < ItemIdxEquipAttrLen {
			continue
		}

		refixType := model.GetRefixTypeByValue(pro[1])
		if refixType == nil {
			continue
		}

		if pro[0] == int(*attrId) {
			nBaseAttr := LoadPlayerInfoManager.GetAttrResult(refixType,pro[2],nBaseValue)
			switch *refixType {
			case model.RefixTypeVTPercent:
				nRet += int(float64(strengthen.AttrIncRate) /1000.0*float64(nBaseAttr))
			case model.RefixTypeVTValue:
				nRet += int(float64(strengthen.AttrIncRate) /1000.0*float64(nBaseAttr)) + item.StrengthLevel
			}
		}else{
			nBaseAttr := LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrId,constants.GetAttrFlagByValue(pro[0]),
				refixType,pro[1],nBaseValue)
			if nBaseAttr != 0 {
				nRet += int(float64(strengthen.AttrIncRate) /1000.0*float64(nBaseAttr)) + item.StrengthLevel
			}
		}
	}
	return nRet
}

/**
计算使用武器的星级加成的属性值
 */
func (p *itemManager) CalEquipStarAddAttr(player *model.PlayerObject,item *model.CommonItem,attrId *constants.AttrFlag) int {
	if player == nil || item == nil || attrId == nil {
		return 0
	}

	if item.StartLevel <= 0 {
		return 0
	}

	v := pitaya.GetTemplateById(template.EquiplayKey,strconv.FormatInt(int64(item.GetId()),10))
	if v == nil {
		return 0
	}
	equipPlay := v.(*template.EquipPlay)

	v = pitaya.GetTemplateById(template.EquipStarKey,strconv.FormatInt(int64(item.StartLevel + 1),10))
	if v == nil {
		return 0
	}
	equipStar := v.(*template.EquipStar)

	nRet := 0
	nBaseValue := 0
	for i := 1;i<= ItemMaxEquipPlayAttr;i++ {
		pro := p.GetEquipPlayAttrConfig(equipPlay,i)
		if pro == nil || len(pro) < ItemIdxEquipPlayLen {
			continue
		}

		if pro[0] > item.StartLevel {
			continue
		}

		//计算加成属性
		var baseAttr int
		if pro[1] == int(*attrId) {
			baseAttr = LoadPlayerInfoManager.GetAttrResult(model.GetRefixTypeByValue(pro[2]),pro[3],nBaseValue)
		}else{
			baseAttr = LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrId,constants.GetAttrFlagByValue(pro[1]),
				model.GetRefixTypeByValue(pro[2]),pro[3],nBaseValue)
		}

		nRet += int(float64(baseAttr) + float64(p.GetEquipStarAttrIncRateConfig(equipStar,i))/1000.0*float64(baseAttr))
	}
	return nRet
}

/**
获取使用武器的配置
 */
func (p *itemManager) GetEquipPlayAttrConfig(equipPlayer *template.EquipPlay,idx int) []int {
	if equipPlayer == nil || idx > ItemMaxEquipPlayAttr || idx <= 0 {
		return nil
	}

	switch idx {
	case 1:
		return equipPlayer.RefineProperty1
	case 2:
		return equipPlayer.RefineProperty2
	case 3:
		return equipPlayer.RefineProperty3
	case 4:
		return equipPlayer.RefineProperty4
	case 5:
		return equipPlayer.RefineProperty5
	case 6:
		return equipPlayer.RefineProperty6
	}

	return nil
}

/**
获取装备星级属性加成比率值
 */
func (p *itemManager) GetEquipStarAttrIncRateConfig(equipStar *template.EquipStar,idx int) int {
	if equipStar == nil || idx <= 0 || idx > ItemMaxEquipPlayAttr {
		return 0
	}

	switch idx {
	case 1:
		return equipStar.AttrIncRate1
	case 2:
		return equipStar.AttrIncRate2
	case 3:
		return equipStar.AttrIncRate3
	case 4:
		return equipStar.AttrIncRate4
	case 5:
		return equipStar.AttrIncRate5
	case 6:
		return equipStar.AttrIncRate6
	}

	return 0
}

/**
从数据库中加载背包数据
 */
func (p *itemManager) LoadItemFromDB(player *model.PlayerObject) (bool,error) {
	//加载物品
	v,err := dao.ItemDao.Get(&pojo.ItemData{
		PlayerGuid: player.GetGuid(),
	})
	if err != nil {
		logger.Log.Errorf("[ItemManager] LoadItemFromDB failed,error:%s",err.Error())
		return false,err
	}

	var itemData *pojo.ItemData
	if v == nil {
		itemData = &pojo.ItemData{
			PlayerGuid: player.GetGuid(),
		}
	}else {
		itemData = v.(*pojo.ItemData)
	}

	//加载背包
	bag := player.Bag
	if bag == nil {
		bag = model.NewPlayerBag()
		player.Bag = bag
	}

	//反序列化背包物品
	bag.UnSerializeData(itemData)
	//反序列化被删除的物品
	bag.UnSerializeDeleteData(itemData)
	//设置背包购买的内容
	bag.BuyItemData = model.UnSerializeBuyItemData(itemData.BuyItems)
	return true,nil
}

/**
初始化角色武器
 */
func (p *itemManager) InitPlayerEquip(player *model.PlayerObject) error {
	if player == nil || player.Bag == nil {
		return nil
	}

	v := pitaya.GetTemplateById(template.ConstantKey,constants.ParamKeyDefaultWeapon)
	if v == nil {
		return nil
	}

	defaultWeapon := v.(*template.Constant)
	weaponIds := defaultWeapon.Constant7
	if len(weaponIds) < player.GetCareerId() {
		return nil
	}

	equip,err := p.CreateItem(weaponIds[player.GetCareerId()-1],1,true)
	if err != nil {
		logger.Log.Errorf("[ItemManager] InitPlayerEquip failed,error:%s",err.Error())
		return err
	}

	if equip == nil || equip.ItemGuid <= 0 {
		return nil
	}

	v = pitaya.GetTemplateById(template.EquipKey,strconv.FormatInt(int64(equip.TemplateId),10))
	if v == nil {
		return nil
	}

	equipCfg := v.(*template.Equip)
	equip.ProTime = util.Now()
	equip.SetBody(constants.StateTrue)
	player.Bag.Items[equip.ItemGuid] = equip
	player.Bag.BodyEquips[equipCfg.Postion] = equip.ItemGuid
	player.Bag.SetModify(true)


	return err
}

/**
创建物品的通用房间
@param nItemId 物品templateId
@param nItemNum 物品数量
@param isCreateGuid 是否给物品分配guid
 */
func (p *itemManager) CreateItem(nItemId,nItemNum int,isCreateGuid bool) (*model.CommonItem,error) {
	if nItemNum <= 0 {
		return nil,nil
	}

	v := pitaya.GetTemplateById(template.ItemKey,strconv.FormatInt(int64(nItemId),10))
	if v == nil {
		return nil,nil
	}

	rItem := v.(*template.Item)
	guid := int64(0)
	var err error
	if isCreateGuid {
		guid,err = GuidGeneratorManager.GenGuid(int(constants.GuidTypeItem))
		if err != nil {
			logger.Log.Errorf("[ItemManager] CreateItem failed,error:%s",err.Error())
			return nil,err
		}
	}

	nMaxNum := rItem.Composition

	item := model.NewCommonItem()
	item.InitData(rItem)
	item.TemplateId = nItemId
	if nMaxNum > 0 {
		if nMaxNum >= nItemNum {
			item.StackCount = nItemNum
		}else{
			item.StackCount = nMaxNum
		}
	}else{
		if rItem.Type == int(constants.ItemTypeVirtual) {
			item.StackCount = nItemNum
		}else{
			item.StackCount = 1
		}
	}

	item.SetBind(constants.StateFalse)
	item.ItemGuid = guid
	p.CheckAndCalEquipRandAttr(item)
	return item,nil
}

/**
计算装备的随机属性
 */
func (p *itemManager) CheckAndCalEquipRandAttr(item *model.CommonItem)  {
	if item == nil {
		return
	}

	if item.MItemCfg.Quality <= int(constants.QualityTypeWhite) {//白色品质
		return
	}

	if item.MItemCfg.Type != int(constants.ItemTypeEquip) {
		return
	}

	v := pitaya.GetTemplateById(template.EquipKey,strconv.FormatInt(int64(item.TemplateId),10))
	if v == nil {
		return
	}
	equipCfg := v.(*template.Equip)

	genRandAttrType := equipCfg.RandPropertyGenType
	if genRandAttrType == int(constants.EquipRandAttrGenTypeInvalid) {
		return
	}else if genRandAttrType == int(constants.EquipRandAttrGenTypeConfig) {//配置表
		p.LoadEquipRandAttrCfg(item,equipCfg)
	}else if genRandAttrType == int(constants.EquipRandAttrGenTypeRand) {//程序随机生成
		//todo:计算程序随机生成随机属性
	}else if genRandAttrType == int(constants.EquipRandAttrGenTypeAuthen) {//鉴定
		return
	}
}

/**
通过配置加载随机属性
 */
func (p *itemManager) LoadEquipRandAttrCfg(item *model.CommonItem,equip *template.Equip)  {
	props := make([][]int,0)
	props = append(props,equip.RandProperty1,equip.RandProperty2,equip.RandProperty3,
		equip.RandProperty4,equip.RandProperty5,equip.RandProperty6)
	idx := 0
	for _,prop := range props {
		if len(prop) < ItemIdxEquipRandAttrLen || prop[0] <= 0 {
			continue
		}

		item.RandAttrType[idx] = byte(prop[0])
		item.RandAttrCal[idx] = byte(prop[1])
		item.RandAttrValue[idx] = prop[2]
		item.RandAttrQuality[idx] = byte(prop[3])

		idx += 1
	}
	item.RandAttrCount = byte(idx)
}

/**
给玩家赠送物品
 */
func (p *itemManager) GiveItem(player *model.PlayerObject,id,num int,logType *constants.LogType) (int,error) {
	if player == nil || id <= 0 || num <= 0 {
		return constants.ItemOptSucc,nil
	}

	v := pitaya.GetTemplateById(template.ItemKey,fmt.Sprintf("%d",id))
	if v == nil {
		return constants.ItemIsNullError,nil
	}

	item := v.(*template.Item)
	if item.MaxOwnNum > 0 {
		num = int(math.Min(float64(num),float64(item.MaxOwnNum - p.GetItemCount(player,id))))
		if num <= 0 {
			if id == GangManager.GetGangCollectionItemId() {
				return constants.GangItemMaxError,nil
			}else {
				return constants.ItemOwnMaxError,nil
			}
		}
	}

	if item.Type == int(constants.ItemTypeVirtual) {
		switch item.SubType {
		case int(constants.VirtualTypeIngot):

		case int(constants.VirtualTypeBindIngot):


		case int(constants.VirtualTypeCoin):

		case int(constants.VirtualTypeSKillPoint):

		case int(constants.VirtualTypeGMIngot):

		case int(constants.VirtualTypeExp):

		case int(constants.VirtualTypeEquipEssence):

		case int(constants.VirtualTypeSoulEssence):

		case int(constants.VirtualTypeCardEssence):

		case int(constants.VirtualTypeGangContri):

		case int(constants.VirtualTypeXianYuan):

		case int(constants.VirtualTypeArenaMoney):

		case int(constants.VirtualTypePreStige):

		case int(constants.VirtualTypeBetIntegral):

		}
	}else{

	}

	return 0, nil
}

/**
获取玩阿基啊某个物品的数量
 */
func (p *itemManager) GetItemCount(player *model.PlayerObject,id int) int {
	if player == nil || id <= 0 {
		return 0
	}

	v := pitaya.GetTemplateById(template.ItemKey,fmt.Sprintf("%d",id))
	if v == nil {
		return 0
	}

	item := v.(*template.Item)
	if item.Type == int(constants.ItemTypeVirtual) {
		switch item.SubType {
		case int(constants.VirtualTypeIngot):
			return player.PlayerData.BankMoney
		case int(constants.VirtualTypeBindIngot):
			return player.PlayerData.BindBankMoney
		case int(constants.VirtualTypeCoin):
			return player.PlayerData.Money
		case int(constants.VirtualTypeSKillPoint):
			return player.PlayerData.SkillPoint
		case int(constants.VirtualTypeGMIngot):
			return player.PlayerData.GmIngot
		case int(constants.VirtualTypeExp):
			return player.PlayerData.PlayerExp
		case int(constants.VirtualTypeEquipEssence):
			return player.PlayerData.EquipEssence
		case int(constants.VirtualTypeSoulEssence):
			return player.PlayerData.SoulEssence
		case int(constants.VirtualTypeCardEssence):
			return player.PlayerData.CardEssence
		case int(constants.VirtualTypeGangContri):
			return player.GangContribution
		case int(constants.VirtualTypeXianYuan):
			return player.PlayerData.Xianyuan
		case int(constants.VirtualTypeArenaMoney):
			return player.PlayerData.ArenaMoney
		case int(constants.VirtualTypePreStige):
			return player.PlayerData.Prestige
		case int(constants.VirtualTypeBetIntegral):
			return player.PlayerData.BetIntegral
		}
	}else{
		return p.GetNotVirtualItemCount(player.Bag,id)
	}
	return 0
}

/**
不是虚拟物品的数量
 */
func (p *itemManager) GetNotVirtualItemCount(bag *model.PlayerBag,id int) int {
	if bag == nil || id <= 0 || len(bag.BagItems) <= 0{
		return 0
	}

	rs := 0
	for _,guid := range bag.BagItems {
		item := bag.GetItemByGuid(guid)
		if item != nil && item.GetId() == id && !item.IsBody() && item.IsValid() {
			rs += item.StackCount
		}
	}
	return rs
}
















